import breve
import random

class Controller(breve.PhysicalControl):
    def __init__(self):
        breve.Control.__init__(self)
        self.setBackgroundColor(breve.vector())
        self.setGravity(breve.vector(0,0,0))  
        self.enableLighting()
        env = Room(breve.vector(20, 0, 20), 5, 
            [GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),GridBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4),ExitBot(4)])
        BlackHole(5).move(breve.vector(25, 2, 0))
        
    def iterate(self):
        breve.Control.iterate(self)
        self.updateNeighbors()
        
    def catchKeyXDown(self):
        for i in breve.allInstances(ExitBot):
            i.getout = True
    
class BlackHole(breve.Mobile):
    def __init__(self, unit):
        breve.Mobile.__init__(self)
        self.setNeighborhoodSize(unit)
        
    def iterate(self):    
        breve.Mobile.iterate(self)
        self.neighborList = self.getNeighbors()
        while len(self.neighborList) > 0: 
            breve.deleteInstance(self.neighborList.pop())

class GridBot(breve.Stationary):
    def __init__(self, unit):
        breve.Stationary.__init__(self)
        self.unit = unit
        self.setShape(breve.createInstances(breve.Cube, 1).initWith(
            breve.vector(unit, unit, unit)))
        self.setColor(breve.vector(1, 0, 0))


class ExitBot(breve.Mobile):
    def __init__(self, unit):
        breve.Mobile.__init__(self)
        self.unit = unit
        self.ticks = 0
        self.enablePhysics()
        self.wander = 0
        self.oldpos = self.getLocation()
        self.getout = False
        self.collision = False
        self.wander_vector = summ = breve.randomExpression(breve.vector(10, 0, 10)) - breve.vector(5, 0, 5)
        self.setShape(breve.createInstances(breve.Sphere, 1).initWith(2.5))
        self.setColor(breve.vector(0, 0, 1))
        
    def iterate(self):
        breve.Mobile.iterate(self)
        self.neighborList = self.getNeighbors()
        self.ticks += 1
        
        
        summ = self.wander_vector
        
        if self.getout:
            if (breve.vector(5,5,-5) - self.getLocation()).length() > 0:
                summ = (breve.vector(20,5,0) - self.getLocation()).normalize() * 10
        
        if self.ticks % 50 == 0:
            
            if (self.oldpos - self.getLocation()).length() == 0:
                print "-",
                self.wander_vector = breve.randomExpression(breve.vector(50, 0, 50)) - breve.vector(25, 0, 25)
                self.wander_vector *= 10
            self.oldpos = self.getLocation()
            summ = self.wander_vector
            
        
        
        avoid_vector = breve.vector(0,0,0)
        for v in self.neighborList:
            if not self.getout and isinstance(v, BlackHole):
                if (self.getLocation() - v.getLocation()).length() > 0:
                    heading = (self.getLocation() - v.getLocation()).normalize()            
                    force = 50/(self.getLocation() - v.getLocation()).length()
                    avoid_vector = avoid_vector + heading*force
                    
            if isinstance(v, ExitBot) or isinstance(v, GridBot):
                if (self.getLocation() - v.getLocation()).length() > 0:
                    heading = (self.getLocation() - v.getLocation()).normalize()            
                    force = 5/(self.getLocation() - v.getLocation()).length()
                    avoid_vector = avoid_vector + heading*force
        
        #avoid_vector = avoid_vector * summ.length()
        
        if avoid_vector.length() > 0:
            avoid_vector = avoid_vector + breve.randomExpression(breve.vector(1, 0, 1)) - breve.vector(.5, 0, .5)
            self.setColor(breve.vector(1,0,0))
        else:
            self.setColor(breve.vector(0,1,0))
            
        self.setVelocity(summ + avoid_vector)
            
class Room(breve.Real):
    def __init__(self, dim, unit, botList):
        breve.Real.__init__(self)
        self.unit = unit
        self.width = dim[0]
        self.height = dim[2]
        self.getController().pointCamera(
            breve.vector(self.width * unit / 2, 0, -self.height * unit / 2), 
            breve.vector(0, 200, self.height * unit))
        self.getController().moveLight(
            breve.vector(self.width * unit / 2, 10, -self.height * unit / 2))
        
 #       for x in range(0, self.width):
 #           Wall(breve.vector(x * unit + unit / 2, unit / 2, 0), 
 #                breve.vector(unit, 2*unit, .1))
 #           Wall(breve.vector(x * unit + unit / 2, unit / 2, -self.height * unit), 
 #                breve.vector(unit, 2*unit, .1))
        
 #       for z in range(0, self.height):
 #           Wall(breve.vector(0, unit / 2, -z * unit - unit / 2), 
 #                breve.vector(.1, 2*unit, unit))
 #           Wall(breve.vector(self.width * unit, unit / 2, -z * unit - unit / 2), 
 #                breve.vector(.1, 2*unit, unit))
                 
        Ground(breve.vector(unit*self.width / 2, -2, -unit*self.height / 2), 
               breve.vector(unit*self.width, 1, unit*self.height))
                
        if len(botList) > self.width * self.height:
            print "Too many bots!"
        self.placeBots(botList)    
        
    def placeBots(self, botList):
        positions = []
        positionCount = self.width * self.height
        
        for i in range(0, positionCount):
            positions.append(True)

        while len(botList) > 0:
            while True:
                spot = random.randint(0, positionCount - 1)
                if positions[spot]: break
                
            positions[spot] = False    
            bot = botList.pop()
            bot.setNeighborhoodSize(6)
            bot.move(breve.vector(int(spot % self.height) * self.unit + self.unit / 2, self.unit / 2, 
                                 -int(spot / self.height) * self.unit - self.unit / 2))

    def getWidth(self): return self.width
    def getHeight(self): return self.height
    def getUnit(self): return self.unit
    
class Obstruction(breve.Stationary):
    def __init__(self, position, dimension, color):
        breve.Stationary.__init__(self)
        self.setTexture(-1)
        self.setShape(breve.createInstances(breve.Cube, 1).initWith(dimension))
        self.setColor(color)
        self.move(position)
    
class Wall(Obstruction):
    def __init__(self, position, dimension):
        Obstruction.__init__(self, position, dimension, breve.vector(1.0, 1.0, 1.0))
        self.setBitmapTransparency(0.5)    
        
class Ground(Obstruction):
    def __init__(self, position, dimension):
        Obstruction.__init__(self, position, dimension, breve.vector(0.0,.3, 0.0))
        self.setBitmapTransparency(0.8)
        
Controller()